package com.tlvip.design.singleton.lazy;

/**
 * <p>description：</p>
 * <p>
 * 涉及的知识点
 * 模式定义/应用场景/类图分析
 * 字节码知识/字节码指令/重排序
 * 类加载机制
 * JVM序列化机制
 * 单例模式在Spring框架 & JDK框架中应用
 * <p>
 * 模式定义
 * 保证一个类只有一个实例，并且提供一个全局访问点
 * <p>
 * 场景
 * 重量级对象，不需要多个实例，如线程池，数据库连接池
 *
 *
 * <p>copyright： copyright(C)2016-2099</p>
 * <p>Life is short,we need passion</p>
 * <p>Summary： </p>
 * <p>instructions： </p>
 * Date 2021/8/15</p>
 * Author mac
 *
 * @version 1.0
 */
public class TestLazySingleton {
    public static void main(String[] args) {
        new Thread(() -> {
            System.out.println(LazySingleton.getInstance());
        }).start();

        new Thread(() -> {
            System.out.println(LazySingleton.getInstance());
        }).start();
    }
}

class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {

    }

    // 存在线程安全问题，增加synchronized后，可以解决问题，但会引发性能问题
    public static LazySingleton getInstance() {
        if (instance == null) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            instance = new LazySingleton();
        }
        return instance;
    }
}

class LazySingletonDoubleCheck {
    private static LazySingletonDoubleCheck instance;

    private LazySingletonDoubleCheck() {
    }

    public static LazySingletonDoubleCheck getInstance() {
        // 双重检查方式，防止多个线程同时进入getInstance
        if (instance == null) {
            synchronized (LazySingletonDoubleCheck.class) {
                if (null == instance) {
                    // 在字节码层面还是会存在问题
                    // javap -p -v xx.class 到对应目录下执行
                    // 1.分配空间 2.引用赋值 3.初始化  可能会产生对象未初始化，将引用分配出去，导致对象未完整的初始化就暴露出去
                    // 指令优化 如 未能满足预期，可能引发问题。
                    // 可以使用volatile 关键字修饰对象，保证指令不被重排序

                    instance = new LazySingletonDoubleCheck();
                }
            }
        }
        return instance;
    }
}
